package utils

import (
	"errors"
	"time"

	"github.com/dgrijalva/jwt-go"
)

type JwtConfig struct {
	Secret     []byte
	JwtDueTime time.Duration
}

type jwtUtil struct {
}

var (
	JwtUtil = &jwtUtil{}
)
var jwtConfig *JwtConfig

func InitJwt(config *JwtConfig) {
	jwtConfig = config
}

func (this *jwtUtil) GetJwtConfig() *JwtConfig {
	return jwtConfig
}

func (this *jwtUtil) GenerateToken(claims *jwt.StandardClaims) (string, error) {
	nowTime := time.Now()
	expireTime := nowTime.Add(jwtConfig.JwtDueTime * time.Hour)
	claims.ExpiresAt = expireTime.Unix()
	tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	token, err := tokenClaims.SignedString(jwtConfig.Secret)
	return token, err
}

func (this *jwtUtil) GenerateTokenWithMapClaims(claims jwt.MapClaims) (string, error) {
	nowTime := time.Now()
	claims["exp"] = nowTime.Add(jwtConfig.JwtDueTime * time.Hour).Unix()
	claims["iat"] = nowTime.Unix()
	token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(jwtConfig.Secret)
	return token, err
}

func (this *jwtUtil) ParseToken(token string, claims *jwt.StandardClaims) error {
	tokenClaims, err := jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (interface{}, error) {
		return jwtConfig.Secret, nil
	})
	if tokenClaims != nil {
		if c, ok := tokenClaims.Claims.(jwt.StandardClaims); ok && tokenClaims.Valid {
			*claims = c
			return nil
		}
	}
	return err
}

func (this *jwtUtil) ParseTokenWithMapClaims(token string) (result jwt.MapClaims, err error) {
	var tokenClaims *jwt.Token
	tokenClaims, err = jwt.ParseWithClaims(token, jwt.MapClaims{}, func(token *jwt.Token) (interface{}, error) {
		return jwtConfig.Secret, nil
	})
	if err == nil {
		if c, ok := tokenClaims.Claims.(jwt.MapClaims); ok && tokenClaims.Valid {
			result = c
		} else {
			err = errors.New("token is invalid")
		}
	}
	return
}
